#include "Ctrl/SelectionModel.hpp"
#include "Model/CaseEntity.hpp"
#include <boost/test/auto_unit_test.hpp>

namespace
{

using namespace Ctrl;
using namespace Model;

class DummyCaseEntity: public CaseEntity
{
};

struct TestFixture
{
	DummyCaseEntity e1, e2, e3, e4, e5;
	std::list< CaseEntity*> l1_3;	// e1, e2, e3
	std::list< CaseEntity*> l1_4;	// e1, e2, e3, e4
	std::list< CaseEntity*> lRepeating; // e1, e1, e2, e3
	std::list< CaseEntity*> lEmpty;	// empty list

	TestFixture()
	{
		l1_3.push_back( &e1); l1_3.push_back( &e2); l1_3.push_back( &e3);
		l1_4.push_back( &e1); l1_4.push_back( &e2); l1_4.push_back( &e3); l1_4.push_back( &e4);
		lRepeating.push_back( &e1); lRepeating.push_back( &e2); lRepeating.push_back( &e3); lRepeating.push_back( &e1);
	}
};

BOOST_AUTO_TEST_CASE( testInitialization)
{
	SelectionModel model;
	BOOST_CHECK( model.isEmpty());
}

// ---------------------------------------------------------------------------------------------------------------------

BOOST_AUTO_TEST_CASE( testMergingElement)
{
	TestFixture f;
	SelectionModel model;
	BOOST_CHECKPOINT( "Testing merging new element");
	model.mergeSelection( &f.e1);
	BOOST_CHECK( model.isSelected( &f.e1));
	BOOST_CHECK_EQUAL( 1, model.size());
	model.mergeSelection( &f.e2);
	BOOST_CHECK( model.isSelected( &f.e1));
	BOOST_CHECK( model.isSelected( &f.e2));
	BOOST_CHECK_EQUAL( 2, model.size());

	BOOST_CHECKPOINT( "Testing merging existing element");
	model.mergeSelection( &f.e1);
	BOOST_CHECK_EQUAL( 2, model.size());
	BOOST_CHECK( model.isSelected( &f.e1));
	BOOST_CHECK( model.isSelected( &f.e2));
}

// ---------------------------------------------------------------------------------------------------------------------

BOOST_AUTO_TEST_CASE( testMergingList)
{
	TestFixture f;
	SelectionModel model;

	BOOST_CHECKPOINT( "Testing merging list with new elements only");
	model.mergeSelection( &f.e5);
	model.mergeSelection( f.l1_3);
	BOOST_CHECK_EQUAL( 4, model.size());
	BOOST_CHECK( model.isSelected( &f.e1));
	BOOST_CHECK( model.isSelected( &f.e2));
	BOOST_CHECK( model.isSelected( &f.e3));
	BOOST_CHECK( model.isSelected( &f.e5));

	BOOST_CHECKPOINT( "Testing merging empty list");
	model.mergeSelection( f.lEmpty);
	BOOST_CHECK_EQUAL( 4, model.size());
	BOOST_CHECK( model.isSelected( &f.e1));
	BOOST_CHECK( model.isSelected( &f.e2));
	BOOST_CHECK( model.isSelected( &f.e3));
	BOOST_CHECK( model.isSelected( &f.e5));

	BOOST_CHECKPOINT( "Testing merging when list contains existing elements");
	model.mergeSelection( f.l1_4);
	BOOST_CHECK_EQUAL( 5, model.size());
	BOOST_CHECK( model.isSelected( &f.e1));
	BOOST_CHECK( model.isSelected( &f.e2));
	BOOST_CHECK( model.isSelected( &f.e3));
	BOOST_CHECK( model.isSelected( &f.e4));
	BOOST_CHECK( model.isSelected( &f.e5));

	BOOST_CHECKPOINT( "Testing merging when list contains duplicate elements");
	model.clear();
	model.mergeSelection( f.lRepeating);
	BOOST_CHECK_EQUAL( 3, model.size());
	BOOST_CHECK( model.isSelected( &f.e1));
	BOOST_CHECK( model.isSelected( &f.e2));
	BOOST_CHECK( model.isSelected( &f.e3));
}

// ---------------------------------------------------------------------------------------------------------------------

BOOST_AUTO_TEST_CASE( testReplacingElement)
{
	TestFixture f;
	SelectionModel model;

	BOOST_CHECKPOINT( "Testing replacing new element");
	model.mergeSelection( &f.e5);
	model.replaceSelection( &f.e1);
	BOOST_CHECK_EQUAL( 1, model.size());
	BOOST_CHECK( model.isSelected( &f.e1));
	BOOST_CHECK( !model.isSelected( &f.e5));

	BOOST_CHECKPOINT( "Testing replacing when new element was also part of the old selection");
	model.clear();
	model.mergeSelection( &f.e5);
	model.mergeSelection( &f.e1);
	model.replaceSelection( &f.e1);
	BOOST_CHECK_EQUAL( 1, model.size());
	BOOST_CHECK( model.isSelected( &f.e1));
	BOOST_CHECK( !model.isSelected( &f.e5));
}

// ---------------------------------------------------------------------------------------------------------------------

BOOST_AUTO_TEST_CASE( testReplacingList)
{
	TestFixture f;
	SelectionModel model;

	BOOST_CHECKPOINT( "Testing replacing list with new elements only");
	model.mergeSelection( &f.e5);
	model.replaceSelection( f.l1_3);
	BOOST_CHECK_EQUAL( 3, model.size());
	BOOST_CHECK( model.isSelected( &f.e1));
	BOOST_CHECK( model.isSelected( &f.e2));
	BOOST_CHECK( model.isSelected( &f.e3));
	BOOST_CHECK( !model.isSelected( &f.e5));

	BOOST_CHECKPOINT( "Testing replacing empty list");
	model.replaceSelection( f.lEmpty);
	BOOST_CHECK_EQUAL( 0, model.size());
	BOOST_CHECK( !model.isSelected( &f.e1));
	BOOST_CHECK( !model.isSelected( &f.e2));
	BOOST_CHECK( !model.isSelected( &f.e3));

	BOOST_CHECKPOINT( "Testing replacing when list contains existing elements");
	model.mergeSelection( f.l1_4);
	model.replaceSelection( f.l1_3);
	BOOST_CHECK_EQUAL( 3, model.size());
	BOOST_CHECK( model.isSelected( &f.e1));
	BOOST_CHECK( model.isSelected( &f.e2));
	BOOST_CHECK( model.isSelected( &f.e3));
	BOOST_CHECK( !model.isSelected( &f.e4));

	BOOST_CHECKPOINT( "Testing replacing when list contains duplicate elements");
	model.replaceSelection( f.lRepeating);
	BOOST_CHECK_EQUAL( 3, model.size());
	BOOST_CHECK( model.isSelected( &f.e1));
	BOOST_CHECK( model.isSelected( &f.e2));
	BOOST_CHECK( model.isSelected( &f.e3));
}

// ---------------------------------------------------------------------------------------------------------------------

BOOST_AUTO_TEST_CASE( testUnselectElement)
{
	TestFixture f;
	SelectionModel model;
	model.replaceSelection( f.l1_4);

	BOOST_CHECKPOINT( "Testing unselecting existing element");
	model.unselect( &f.e4);
	BOOST_CHECK_EQUAL( 3, model.size());
	BOOST_CHECK( model.isSelected( &f.e1));
	BOOST_CHECK( model.isSelected( &f.e2));
	BOOST_CHECK( model.isSelected( &f.e3));
	BOOST_CHECK( !model.isSelected( &f.e4));

	BOOST_CHECKPOINT( "Testing unselecting inexistent element");
	model.unselect( &f.e5);
	BOOST_CHECK_EQUAL( 3, model.size());
	BOOST_CHECK( model.isSelected( &f.e1));
	BOOST_CHECK( model.isSelected( &f.e2));
	BOOST_CHECK( model.isSelected( &f.e3));
	BOOST_CHECK( !model.isSelected( &f.e5));
}

// --------------------------------------------------------------------------------------------------------------------

BOOST_AUTO_TEST_CASE( testUnselectList)
{
	TestFixture f;
	SelectionModel model;
	model.replaceSelection( &f.e5);

	BOOST_CHECKPOINT( "Testing unselecting list with inexistent elements only");
	model.unselect( f.l1_3);
	BOOST_CHECK_EQUAL( 1, model.size());
	BOOST_CHECK( model.isSelected( &f.e5));
	BOOST_CHECK( !model.isSelected( &f.e1));
	BOOST_CHECK( !model.isSelected( &f.e2));
	BOOST_CHECK( !model.isSelected( &f.e3));

	BOOST_CHECKPOINT( "Testing unselecting empty list");
	model.unselect( f.lEmpty);
	BOOST_CHECK_EQUAL( 1, model.size());
	BOOST_CHECK( model.isSelected( &f.e5));
	BOOST_CHECK( !model.isSelected( &f.e1));
	BOOST_CHECK( !model.isSelected( &f.e2));
	BOOST_CHECK( !model.isSelected( &f.e3));

	BOOST_CHECKPOINT( "Testing unselecting when list contains existing elements");
	model.replaceSelection( f.l1_4);
	model.unselect( f.l1_3);
	BOOST_CHECK_EQUAL( 1, model.size());
	BOOST_CHECK( model.isSelected( &f.e4));
	BOOST_CHECK( !model.isSelected( &f.e1));
	BOOST_CHECK( !model.isSelected( &f.e2));
	BOOST_CHECK( !model.isSelected( &f.e3));

	BOOST_CHECKPOINT( "Testing unselecting when list contains duplicate elements");
	model.replaceSelection( f.l1_4);
	model.unselect( f.lRepeating);
	BOOST_CHECK_EQUAL( 1, model.size());
	BOOST_CHECK( model.isSelected( &f.e4));
	BOOST_CHECK( !model.isSelected( &f.e1));
	BOOST_CHECK( !model.isSelected( &f.e2));
	BOOST_CHECK( !model.isSelected( &f.e3));
}

// --------------------------------------------------------------------------------------------------------------------

BOOST_AUTO_TEST_CASE( testClear)
{
	TestFixture f;
	SelectionModel model;

	BOOST_CHECKPOINT( "Testing clearing empty list");
	model.clear();
	BOOST_CHECK_EQUAL( 0, model.size());

	BOOST_CHECKPOINT( "Testing clearing not-empty list");
	model.mergeSelection( f.l1_3);
	model.clear();
	BOOST_CHECK_EQUAL( 0, model.size());
}

} // namespace
